/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package downloadmanager;

import downloadmanager.component.MultiSegmentProgressBar;
import downloadmanager.downloader.Downloader;
import downloadmanager.downloader.DownloaderState;
import downloadmanager.event.XEventListener;
import java.util.*;
import javax.swing.table.*;

// This class manages the download table's data.
class DownloadsTableModel extends AbstractTableModel {

    // These are the names for the table's columns.
    private static final String[] columnNames = {"URL", "Size", "%", "Speed", "Progress", "State", "Save To"};
    // These are the classes for each column's values.
    private static final Class[] columnClasses = {String.class,
        String.class, String.class, String.class, MultiSegmentProgressBar.class, String.class, String.class};
    private List<Downloader> downloadList = new ArrayList<Downloader>();
    HashMap<Downloader, XEventListener<Object>> progressChangeListener = new HashMap<Downloader, XEventListener<Object>>();
    HashMap<Downloader, XEventListener<DownloaderState>> stateChangeListener = new HashMap<Downloader, XEventListener<DownloaderState>>();

    public List<Downloader> getDownloadList() {
        return downloadList;
    }

    public void addDownload(final Downloader download) {

        downloadList.add(download);
        // Fire table row insertion notification to table.
        fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1);
        progressChangeListener.put(download, new XEventListener<Object>() {

            public void eventFired(Object sender, Object args) {
                int index = downloadList.indexOf(download);
                fireTableRowsUpdated(index, index);
            }
        });
        download.getProgressSegmentList().ValueChange.subscribe(progressChangeListener.get(download));

        stateChangeListener.put(download, new XEventListener<DownloaderState>() {

            public void eventFired(Object sender, DownloaderState args) {
                int index = downloadList.indexOf(download);
                fireTableRowsUpdated(index, index);
            }
        });
        download.StateChanged.subscribe(stateChangeListener.get(download));

    }

    void removeDownload(Downloader download) {

        int index = downloadList.indexOf(download);
        downloadList.remove(download);
        // Fire table row insertion notification to table.
        download.getProgressSegmentList().ValueChange.unsubscribe(progressChangeListener.get(download));
        download.StateChanged.unsubscribe(stateChangeListener.get(download));
        fireTableRowsDeleted(index, index);
    }

    public Downloader getDownload(int row) {
        return downloadList.get(row);
    }

    public void clearDownload(int row) {
        downloadList.remove(row);

        // Fire table row deletion notification to table.
        fireTableRowsDeleted(row, row);
    }

    public int getColumnCount() {
        return columnNames.length;
    }

    @Override
    public String getColumnName(int col) {
        return columnNames[col];
    }

    @Override
    public Class getColumnClass(int col) {
        return columnClasses[col];
    }

    public int getRowCount() {
        return downloadList.size();
    }

    private String getReadableSize(long size) {
        if (size < 1024) {
            return String.format("%d bytes", size);
        }
        if (size < 1024 * 1024) {
            return String.format("%.2f kB", 1.0 * size / 1024);
        }
        if (size < 1024 * 1024 * 1024) {
            return String.format("%.2f MB", 1.0 * size / 1024 / 1024);
        }
        return String.format("%.2f GB", 1.0 * size / 1024 / 1024);
    }

    private String getReadableSpeed(double rate) {
        if (rate < 1024) {
            return String.format("%.0f byte(s)/s", rate);
        }
        if (rate < 1024 * 1024) {
            return String.format("%.2f kB/s", rate / 1024);
        }
        return String.format("%.2f MB/s", rate / 1024 / 1024);

    }

    public Object getValueAt(int row, int col) {

        Downloader download = downloadList.get(row);
        switch (col) {
            case 0: // URL
                return download.getURL();
            case 1: // Size
                return getReadableSize(download.getFileSize());
            case 2: // %
                if (download.getFileSize() == 0) {
                    return "";
                }
                return String.format("%.2f%%", 100.0 * download.getTransfered() / download.getFileSize());
            case 3: // Speed
                switch (download.getState()) {
                    case Working:
                        return getReadableSpeed(download.getRate());
                    default:
                        return "";
                }
            case 4: // Progress
                return download.getProgressSegmentList();
            case 5: // State
                return download.getState();
            case 6: //Save To
                return download.getLocalFile();
        }
        return "";
    }
}
